import subprocess
import threading
import sys
import os
import tempfile

class MTPFileCopier():
    
    def __init__(self):
        self._observers = []
        
    def add_observer(self, observer):
        self._observers.append(observer)
        
    def detect(self, progress_poker=None):
    
        pargs = ['mtp-detect']
        
        process = subprocess.Popen(pargs, 
                                   stdout=subprocess.PIPE)
        
        self._detected = False
        
        def read_stdout():
            file = process.stdout
            line_buf = []
            seen_raw_device = False
            while True:
                char = file.read(1)
                
                if progress_poker:
                    progress_poker()
                    
                if char == '':
                    break
                
                if char == '\n':
                    line = ''.join(line_buf)
                    print 'mtp-detect: %s' % line
                    if line.find('Listing raw device(s)') == 0:
                        seen_raw_device = True
                    elif seen_raw_device:
                        idx = line.find('  Found ')
                        if idx > 0:
                            self._detected = True
                    
                    line_buf = []
                else:
                    line_buf.append(char)
                    
        stdout_thread = threading.Thread(name='detect_thread', target=read_stdout)
        stdout_thread.start()
                    
        process.wait()
        stdout_thread.join()
        
        return self._detected
    
    def copy(self, srcfilename, destfilename):
        
        tempdir = tempfile.mkdtemp()
        linkedfilename = tempdir + '/' + destfilename + ".avi"
        os.symlink(srcfilename, linkedfilename)
        
        pargs = ['mtp-sendfile', linkedfilename, destfilename]
        
        print ' '.join(pargs)
        
        process = subprocess.Popen(pargs, 
                                   stdout=subprocess.PIPE, 
                                   stderr=subprocess.PIPE)
        
        observers = self._observers
        
        def read_stdout():
            file = process.stdout
            
            seen_brack = False
            token_buf = []
            all_chars = []
            cur_line = []
            
            while (True):
                char = file.read(1)
                all_chars.append(char)
                cur_line.append(char)
                
                if char == '':
                    break
                
                if char == '\n':
                    line = ''.join(cur_line)
                    
                    sys.stdout.write(line)
                    if line.find('No devices.') != -1:
                        self._raise_error(NoDeviceException())
                    cur_line = []
                
                elif seen_brack:
                    
                    if char == ')':
                        token = ''.join(token_buf)
                        perc_idx = token.find('%')
                        value = token[0:perc_idx]
                        
                        for ob in observers:
                            try:
                                ob.update_progress(int(value))
                            except ValueError:
                                pass 
                    
                        seen_brack = False
                        token_buf = []
                    else:
                        token_buf.append(char)
                
                elif char == '(':
                    seen_brack = True
                
#            print ''.join(all_chars)
                
        
        def read_stderr():
            file = process.stderr
            
            while True:
                char = file.read(1)
                
                if char == '':
                    break
                
                print char
        
        stdout_thread = threading.Thread(name='copy_stdout', target=read_stdout)
        stderr_thread = threading.Thread(name='copy_stderr', target=read_stderr)
        
        stderr_thread.start()
        stdout_thread.start()
        
        process.wait()

    def _raise_error(self, error):
        for ob in self._observers:
            try:
                ob.report_error(error, fatal=True)
            except:
                print 'Error report error to %s' % ob

class NoDeviceException(Exception):
    pass

if __name__ == '__main__':
    copier = MTPFileCopier()
    
    class Observer:
        def update_progress(self, value):
            print value
            
        def report_error(self, error, fatal):
            print "ERROR: %s" % error
    
    copier.add_observer(Observer())

    if copier.detect():
        copier.copy('/home/nick/Music/Luke Buda/the c sides/05 - Seaside.mp3', 'copied-file.MP3')
    else:
        print 'no device attached'